11. Migration to Java 9 Modules
Migration to Java 9 Modules
ND079 JPND C3 L3 A09 Mitigation To Java 9 Modules V3
Should You Upgrade
You don't need to upgrade to modules just to use a newer version of Java. All versions work without a module-info.java.
When to **Avoid **Modules:
- Many Legacy Dependencies
- Infrequent Change
- Not Shared
When to **Use **Modules:
- New Projects
- Application Used By Other Applications
- Hide Internal Methods and Data Types
Preparing To Upgrade
- Review Test Coverage
- Upgrade Tooling
- IntelliJ 2018.2+
- Maven 3.5.0+
- maven-compiler-plugin 3.8.0+
- maven-surefire-plugin 2.22.0+
- Update Dependencies
Update Language Level
Download the target JDK and update the pom.xml. For example:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>14</maven.compiler.source>
<maven.compiler.target>14</maven.compiler.target>
</properties>
Resolve Duplicate Packages
Placing multiple projects with the same package on the classpath is not a problem, because the packages simply combine. You cannot place packages with the same name on the Module path, however. If you have different projects that share a package name, you will need to refactor one of them to use a different package name.
Create module-info.java
- Create a minimal
module-info.java
in thesrc/main/java
directory containing only your new module name. - Resolve errors in IntelliJ. You should be able to mouseover or use the "quick fix" key bind to automatically add missing
requires
,exports
, andopens
statements. - Build the project with maven using
mvn package
What Can Go Wrong?
ND079 JPND C3 L3 A10 What Can Go Wrong Migration To Java 9 Modules
Common Problems
Most of the problems with Modules revolve around the relationship between dependencies and transitive dependencies in which one or both are non-modular projects.
Dependencies Use Reflection
If dependencies access your class via reflection, you may not notice until you run the project.
Unable to make public com.udacity.jpnd.Foo() accessible: module com.udacity.jpnd does not "exports com.udacity.jpnd" to module com.other.module
- Module ‘com.other.module’ is trying to access ‘com.udacity.jpnd’.
- Resolve by exporting or opening the required package.
Modular Transitive Dependencies of non-modular Dependencies
If your non-modular dependencies reference transitive dependencies that are modular, those dependencies will become modules and be inaccessible to your module unless you explicitely require
them.
This issue may not be apparent until you run the program and you receive a NoClassDefFoundError
when the engine
module tries to execute some method from piston
and can't find it.
You may encounter this error in the final project when including Amazon SDK dependencies:
https://github.com/aws/aws-sdk-java-v2/issues/1869
Reflection Access to Non-Modules
You cannot open your module to the Unnamed Module. If a transitive dependency requires reflection access to your module, it will be unable to access that package unless you fully open the package to everyone.
This occurs in some Test frameworks that use reflection libraries as transitive dependencies. One solution for this case is to limit the scope in which you open your package by only opening the module during the execution of the testing plugin.
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<argLine>
--add-opens com.udacity.jpnd.mymodule/com.udacity.jpnd.mypackage=ALL-UNNAMED
</argLine>
</configuration>
</plugin>
Libraries Removed from JDK
Some libraries are not exposed by the core JDK as modules. If you relied on one of the JDK internal libraries in the javax
or com.sun
packages, you may encounter ClassNotFoundException
trying to access those classes. You can check for these classes using:
jdeps -jdkinternals pathToClasses
Migration Guides
It's hard to address all possible issues, so definitely consult some migration guides such as:
https://docs.oracle.com/en/java/javase/11/migrate/index.html